package com.coocaa.ops.admin.v1.auth.sys.service.impl;


import com.coocaa.ops.admin.v1.auth.sys.biz.ISysLogLoginBiz;
import com.coocaa.ops.admin.v1.auth.sys.biz.ISysMenuBiz;
import com.coocaa.ops.admin.v1.auth.sys.biz.ISysRunBiz;
import com.coocaa.ops.admin.v1.auth.sys.provider.ISysAuthorizeProvider;
import com.coocaa.ops.admin.base.util.WebUtil;
import com.coocaa.ops.admin.base.annotation.Config;
import com.coocaa.ops.admin.v1.auth.sys.constant.LoginStatus;
import com.coocaa.ops.admin.v1.auth.sys.service.ISysAuthorizeService;
import org.apache.commons.collections4.CollectionUtils;
import com.coocaa.ops.common.core.biz.auth.entity.SysMenuEntity;
import com.coocaa.ops.common.core.biz.auth.entity.SysRunEntity;
import com.coocaa.ops.common.core.biz.auth.entity.SysUserEntity;
import com.coocaa.ops.common.tool.exception.LoginException;
import com.coocaa.ops.common.tool.http.HttpSessionUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.*;

/**
 * @author bijiahao
 * @date : 2018/7/3.
 * @description: 系统管理- 权限
 */
@Slf4j
@Service
public class SysAuthorizeServiceImpl implements ISysAuthorizeService {
    @Autowired
    private ISysMenuBiz sysMenuBiz;
    @Autowired
    private ISysRunBiz sysRunBiz;
    @Autowired
    private ISysAuthorizeProvider sysAuthorizeProvider;
    @Autowired
    private ISysLogLoginBiz sysLogLoginBiz;

    /**
     * 登录
     *
     * @param request
     * @param response
     * @return
     */
    @Override
    public Map<String, Object> userLogin(HttpServletRequest request, HttpServletResponse response) throws Exception {
        //登录名
        String userName = request.getParameter("username");
        //域账号用户名
        String ldapName = request.getParameter("ldapName");
        //密码
        String pwd = request.getParameter("password");
        // 获取错误登录次数
        Integer errorNum = (Integer) HttpSessionUtil.getSessionValue(request, userName);
        //获取禁止登录时间
        Date errorTime = (Date) HttpSessionUtil.getSessionValue(request, userName + "_errorTime");
        //限制3次登录失败后，禁止登录时长30分钟
        long limitTime = 30 * 60 * 1000;
        long leftTime = 0;
        if (errorTime != null) {
            leftTime = System.currentTimeMillis() - errorTime.getTime();
        }
        Map<String, Object> result = new HashMap<>(3);

        LoginStatus loginStatus = sysAuthorizeProvider.userLogin(request, response, userName, ldapName, pwd);

        if (loginStatus == LoginStatus.SUCCESS && (leftTime >= limitTime || errorTime == null)) {
            result.put("code", "0");
            result.put("success", true);
            //设置登录数据
            result.put("data", getLoginData(request));
        } else if (loginStatus == LoginStatus.LDAP_ACCOUNT_NO_AUTHORITY) {
            result.put("code", "1001");
            result.put("success", false);
            result.put("msg", "Domain account does not have permission!");
        } else {
            errorNum = errorNum == null ? 1 : errorNum + 1;
            String name = ldapName;
            if (ldapName == null) {
                name = userName == null ? "" : userName;
            }
            result.put("code", "1001");
            result.put("success", false);
            if (errorNum >= 3) {
                if (errorTime == null) {
                    HttpSessionUtil.setSessionValue(request, name + "_errorTime", new Date());
                    result.put("msg", "wrong user name or password!");
                } else if (leftTime <= limitTime) {
                    result.put("msg", "You have failed to log in 3 times in a row, please log in again after 30 minutes! Username or password is wrong!");
                    result.put("enable_login", false);
                }
            } else {
                HttpSessionUtil.setSessionValue(request, name, errorNum);
                result.put("msg", "wrong user name or password!");
            }
        }
        return result;
    }

    @Override
    public void logout(HttpServletRequest request, HttpServletResponse response) throws Exception {
        SysUserEntity user = WebUtil.getCurrentUser(request);
        String loginIp = HttpSessionUtil.getIpAddr(request);
        String userAgent = request.getHeader("user-agent");
        //保存登录日志
        sysLogLoginBiz.saveSysLogLogin(loginIp, user, userAgent);
        HttpSession session = HttpSessionUtil.getSession(request);
        if (null != session) {
            session.invalidate();
        }
        //处理cookie删除问题
        sysAuthorizeProvider.logout(request, response);
        //临时退回首页(重新登陆)
        response.sendRedirect("/");
    }

    /**
     * 获取登录用户指定菜单的操作权限
     *
     * @param clzz
     * @param loginUser
     * @return
     */
    @Override
    public List<SysRunEntity> getMenuTools(Class<?> clzz, SysUserEntity loginUser) {
        if (loginUser == null) {
            //连接已超时
            log.error("当前登陆用户已连接超时");
            return null;
        }
        Config config = clzz.getAnnotation(Config.class);
        Integer menuId = sysMenuBiz.getMenuIdByCategory(config.menuToken());
        List<SysRunEntity> sysRuns;
        if (Objects.equals(loginUser.getSuperAdmin(), 1)) {
            sysRuns = sysRunBiz.listMenuRuns(menuId, true, true, false);
        } else {
            sysRuns = sysRunBiz.listMenuRunsByMenuIdAndRoles(menuId, loginUser.getRoles(), true, true, false);
        }
        return sysRuns;
    }

    /**
     * 获取当前环境及用户信息
     *
     * @param request
     * @return
     */
    @Override
    public Map<String, Object> getEnvironment(HttpServletRequest request) {
        Map<String, Object> data = new HashMap<>(2);
        //设置用户信息
        try {
            data.put("userInfo", getResponseUserInfo(request));
        } catch (LoginException e) {
            data.put("userInfo", null);
        }
        return data;
    }

    /**
     * 获取指定菜单的操作角色权限
     *
     * @param menuElId
     * @param roles
     * @return
     */
    @Override
    public List<SysRunEntity> getMenuTools(String menuElId, List<Integer> roles) {
        Integer menuId = sysMenuBiz.getMenuIdByCategory(new String[]{menuElId});
        List<SysRunEntity> sysRuns;
        sysRuns = sysRunBiz.listMenuRunsByMenuIdAndRoles(menuId, roles, true, false, true);
        return sysRuns;
    }


    @Override
    public String getUserMenusByUser(SysUserEntity user) {
        List<SysMenuEntity> list = new ArrayList<>();
        if (Objects.equals(user.getSuperAdmin(), 1)) {
            Map params = new HashMap(2);
            params.put("disabled", 0);
            params.put("orderByStr", "pid ASC, seq ASC");
            list = sysMenuBiz.getMapper().queryCommonPageList(params);
        } else {
            List<Integer> rids = user.getRoles();
            if (CollectionUtils.isNotEmpty(rids)) {
                list = sysMenuBiz.getMapper().listMenuByRoleIds(rids);
            }
        }
        StringBuffer sb = new StringBuffer();
        sb.append("[");
        sb.append(getMenusToString(list, null));
        sb.append("]");
        return sb.toString().replaceAll(",\"children\":\\[]", "").replaceAll(",]", "]");
    }

    /*************** ===私有方法=== ********************* ===start=== ***************************************/
    /**
     * 获取登录数据
     *
     * @return
     */
    private Map getLoginData(HttpServletRequest request) {
        Map<String, Object> data = new HashMap(2);
        //设置平台类型
        data.put("userInfo", getResponseUserInfo(request));
        return data;
    }

    /**
     * 获取返回前端的用户信息
     *
     * @param request
     * @return
     */
    private SysUserEntity getResponseUserInfo(HttpServletRequest request) {
        SysUserEntity userEntity = WebUtil.getCurrentUser(request);
        SysUserEntity userInfo = new SysUserEntity();
        userInfo.setId(userEntity.getId());
        userInfo.setLoginName(userEntity.getLoginName());
        return userInfo;

    }

    /**
     * 递归生成JSON格式菜单字符串
     *
     * @param menuList
     * @param menuEntity
     * @return
     */
    private String getMenusToString(List<SysMenuEntity> menuList, SysMenuEntity menuEntity) {
        StringBuffer sb = new StringBuffer();
        SysMenuEntity menu;
        if (menuEntity == null) {
            for (SysMenuEntity me : menuList) {
                menu = me;
                if (menu.getPid() == 0) {
                    sb.append("{\"text\":\"");
                    sb.append(me.getMenuName());
                    sb.append("\",\"token\":\"");
                    sb.append(me.getMenuToken());
                    sb.append("\",\"title\":\"");
                    sb.append(me.getMenuName());
                    sb.append("\",\"icon\":\"");
                    sb.append(me.getMenuIcon());
                    sb.append("\",\"url\":\"");
                    sb.append(me.getIframeUrl());
                    sb.append("\",\"children\":[");
                    sb.append(getMenusToString(menuList, menu));
                    sb.append("]");
                    sb.append("},");
                }
            }
        } else {
            for (SysMenuEntity me : menuList) {
                menu = me;
                if (menuEntity.getId().equals(menu.getPid())) {
                    sb.append("{\"text\":\"");
                    sb.append(me.getMenuName());
                    sb.append("\",\"id\":\"");
                    sb.append(me.getMenuToken());
                    sb.append("\",\"iconCls\":\"");
                    sb.append(me.getMenuIcon());
                    sb.append("\",\"attributes\":{");
                    sb.append("\"tabTitle\":\"");
                    sb.append(me.getMenuName());
                    sb.append("\",\"menuId\":\"");
                    sb.append(me.getId());
                    sb.append("\",\"tabIcon\":\"");
                    sb.append(me.getMenuIcon());
                    sb.append("\",\"modle\":\"");
                    sb.append(me.getOpenMode());
                    sb.append("\",\"iframeUrl\":\"");
                    sb.append(me.getIframeUrl());
                    sb.append("\"},\"children\":[");
                    sb.append(getMenusToString(menuList, menu));
                    sb.append("]");
                    sb.append("},");
                }
            }
        }
        return sb.toString();
    }
}
